package top.continew.starter.security.crypto.core;


import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.ReflectUtil;
import java.lang.reflect.Field;
import java.sql.Statement;
import java.util.List;
import org.apache.ibatis.executor.resultset.ResultSetHandler;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.plugin.Intercepts;
import org.apache.ibatis.plugin.Invocation;
import org.apache.ibatis.plugin.Signature;
import org.apache.ibatis.type.SimpleTypeRegistry;
import top.continew.starter.security.crypto.annotation.FieldEncrypt;
import top.continew.starter.security.crypto.autoconfigure.CryptoProperties;
import top.continew.starter.security.crypto.encryptor.IEncryptor;

/**
 * @program: examstarapi
 * @description: 替代框架bug
 * @author: Xiong weiqiang
 * @create: 2025-07-05 16:00
 */
@Intercepts({@Signature(
        type = ResultSetHandler.class,
        method = "handleResultSets",
        args = {Statement.class}
)})
public class MyBatisDecryptInterceptor extends AbstractMyBatisInterceptor implements Interceptor {
    private CryptoProperties properties;

    public MyBatisDecryptInterceptor(CryptoProperties properties) {
        this.properties = properties;
    }

    public MyBatisDecryptInterceptor() {
    }

    public Object intercept(Invocation invocation) throws Throwable {
        Object obj = invocation.proceed();
        if (null != obj && invocation.getTarget() instanceof ResultSetHandler) {
            List<?> resultList = (List)obj;
            for(Object result : resultList) {
                if (result!=null&&!SimpleTypeRegistry.isSimpleType(result.getClass())) {
                    for(Field field : super.getEncryptFields(result)) {
                        IEncryptor encryptor = super.getEncryptor((FieldEncrypt)field.getAnnotation(FieldEncrypt.class));
                        Object fieldValue = ReflectUtil.getFieldValue(result, field);
                        if (null != fieldValue) {
                            String password = (String)ObjectUtil.defaultIfBlank(((FieldEncrypt)field.getAnnotation(FieldEncrypt.class)).password(), this.properties.getPassword());
                            String ciphertext = encryptor.decrypt(fieldValue.toString(), password, this.properties.getPrivateKey());
                            ReflectUtil.setFieldValue(result, field, ciphertext);
                        }
                    }
                }
            }

            return resultList;
        } else {
            return obj;
        }
    }
}
